package com.culture.bootdemo.common.basevo;


import com.culture.bootdemo.common.exception.BusinessException;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.Optional;

/**
 * @author ：wen
 * @date ：Created in 2019/8/2 18:04
 * @description：:
 */
@Slf4j
@Data
@Builder
@ApiModel(description = "响应信息")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @ApiModelProperty(value = "状态返回码", required = true)
    private int errCode;

    @ApiModelProperty(value = "对返回码的文本描述内容", required = true)
    private String errMsg;

    @ApiModelProperty(value = "响应数据")
    private T data;

    @ApiModelProperty(value = "分页信息")
    private T page;

    public Result() {
    }

    public Result(ResultCode resultCode) {
        this(resultCode.code, resultCode.msg);
    }

    public Result(T data) {
        this(ResultCode.SUCCESS, data);
    }

    public Result(ResultCode resultCode, T data) {
        this(resultCode.code, resultCode.msg, data);
    }

    public Result(ResultCode resultCode, T data, T pageData) {
        this(resultCode.code, resultCode.msg, data, pageData);
    }

    public Result(int errCode, String errMsg) {
        this(errCode, errMsg, null);
    }

    public Result(int errCode, String errMsg, T data) {
        this(errCode, errMsg, data, null);
    }

    public Result(int errCode, String errMsg, T data, T page) {
        this.errCode = errCode;
        this.errMsg = errMsg;
        this.data = data;
        this.page = page;
    }


    /**
     * 判断返回是否为成功
     *
     * @param result 响应信息{@code Result}
     * @return 是否成功
     */
    public static boolean isSuccess(@Nullable Result<?> result) {
        return Optional.ofNullable(result)
                .map(r -> r.errCode)
                .map(code -> ResultCode.SUCCESS.code == code)
                .orElse(Boolean.FALSE);
    }


    /**
     * 判断返回是否为成功
     *
     * @param result 响应信息{@code Result}
     * @return 是否成功
     */
    public static boolean isNotSuccess(@Nullable Result<?> result) {
        return !Result.isSuccess(result);
    }


    /**
     * 获取响应码
     *
     * @param result 响应数据
     * @return 响应码
     */
    public static Integer getErrCode(@Nullable Result<?> result) {
        return Optional.ofNullable(result).isPresent() ? Optional.of(result.errCode).get() : ResultCode.FAILURE.code;
    }


    /**
     * 获取响应信息
     *
     * @param result 响应数据
     * @return 响应信息
     */
    public static String getErrMsg(@Nullable Result<?> result) {
        return Optional.ofNullable(result).isPresent() ? Optional.of(result.errMsg).get() : ResultCode.FAILURE.msg;
    }


    /**
     * 获取响应数据 data
     *
     * @param result 响应数据
     * @param <T>    泛型标记
     * @return 泛型对象
     */
    @Nullable
    public static <T> T getData(@Nullable Result<T> result) {
        return Optional.ofNullable(result)
                .filter(r -> r.errCode == ResultCode.SUCCESS.code)
                .map(r -> r.data)
                .orElse(null);
    }


    /**
     * 返回成功
     *
     * @param <T> 泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> success() {
        return new Result<>(ResultCode.SUCCESS);
    }


    /**
     * 返回成功-携带数据
     *
     * @param data 响应数据
     * @param <T>  泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> success(@Nullable T data) {
        return new Result<>(ResultCode.SUCCESS, data);
    }


    /**
     * 返回成功-携带数据
     *
     * @param data     响应数据
     * @param pageData 分页信息
     * @param <T>      泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> success(@Nullable T data, @Nullable T pageData) {
        return new Result<>(ResultCode.SUCCESS, data, pageData);
    }


    /**
     * 根据状态返回成功或者失败
     *
     * @param status 状态 true/false
     * @param errMsg 错误信息
     * @param <T>    泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> status(boolean status, String errMsg) {
        return status ? Result.success() : Result.failure(errMsg);
    }

    /**
     * 根据状态返回成功或者失败
     *
     * @param status     状态 true/false
     * @param resultCode 系统响应码枚举
     * @param <T>        泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> status(boolean status, ResultCode resultCode) {
        return status ? Result.success() : Result.failure(resultCode);
    }


    /**
     * 返回失败信息
     *
     * @param errMsg 错误信息
     * @param <T>    泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> failure(String errMsg) {
        return new Result<>(ResultCode.FAILURE.code, errMsg);
    }


    /**
     * 返回失败信息
     *
     * @param errCode 系统错误响应码
     * @param errMsg  错误信息
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> failure(int errCode, String errMsg) {
        return new Result<>(errCode, errMsg);
    }

    /**
     * 返回失败信息
     *
     * @param resultCode 系统错误响应码枚举
     * @param errMsg     错误信息
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> failure(ResultCode resultCode, String errMsg) {
        return new Result<>(resultCode.code, errMsg);
    }


    /**
     * 返回失败信息
     *
     * @param resultCode 系统响应码枚举
     * @param <T>        泛型标记
     * @return 响应信息 {@code Result}
     */
    public static <T> Result<T> failure(ResultCode resultCode) {
        return new Result<>(resultCode);
    }


    /**
     * 当 result 不成功时：直接抛出失败异常，返回传入的 result。
     *
     * @param result 响应信息 {@code Result}
     */
    public static void throwOnFail(Result<?> result) {
        if (Result.isNotSuccess(result)) {
            throw new BusinessException(Result.getErrMsg(result));
        }
    }


    /**
     * 直接抛出失败异常
     *
     * @param resultCode 系统响应码枚举
     */
    public static void throwOnFail(ResultCode resultCode) {
        throw new BusinessException(resultCode);
    }


    /**
     * 直接抛出失败异常
     *
     * @param errMsg 响应信息
     */
    public static void throwOnFail(String errMsg) {
        throw new BusinessException(errMsg);
    }
}
